import * as THREE from 'three';
// import PinoutLineHandler from '../engine2D-pinout/tools/PinoutLineHandler';

class UtilObj {
    fns = {}
    constructor(){

    }

    setFn(name, fn){
        this.fns[name] = fn;
    }

    getFn(name){
        return this.fns[name];
    }
}

const utilToolObj = new UtilObj;

export {utilToolObj};

export const getPointByDirection = (pointList, direction) => {
    if (!pointList?.length) {
        return;
    }

    let extremePoint = pointList[0];
    let idx = 0;

    for (let i = 1, len = pointList.length; i < len; i++) {
        const point = pointList[i];

        if (direction === 'left' && point.x < extremePoint.x) {
            extremePoint = point;
            idx = i;
        } else if (direction === 'top' && point.y < extremePoint.y) {
            extremePoint = point;
            idx = i;
        } else if (direction === 'right' && point.x > extremePoint.x) {
            extremePoint = point;
            idx = i;
        } else if (direction === 'bottom' && point.y > extremePoint.y) {
            extremePoint = point;
            idx = i;
        }
    }

    return {
        idx,
        extremePoint
    };
}

export const createImageDiv = (className, url, clickCb, defaultHide = false) => {
    const div = document.createElement('div');
    className && div.classList.add(className);
    div.style.backgroundImage = `url(${url})`;
    clickCb && div.addEventListener('click', clickCb);
    if (defaultHide) {
        div.style.display = 'none';
    }
    return div;
};

export const getCenter2D = (v1, v2) => {
    const center = new THREE.Vector2().addVectors(v1, v2);
    center.multiplyScalar(0.5);
    return center;
}

// 简化路径，去除同一直线上的中间点，仅保留该线条的端点
export const simplifyPath2D = (points) => {
    if (!points?.length) {
        return [];
    }
    if (points.length <= 2) {
        return points;
    }

    // 先清除一次相同点
    const uniquePoints = new Map();
    points.forEach(point => {
        const key = `${point.x.toFixed(3)},${point.y.toFixed(3)}`;
        uniquePoints.set(key, point);
    });
    if(uniquePoints.size === 1){
        return points;
    }
    const tmpPoints = Array.from(uniquePoints.values());

    let pt1 = tmpPoints[0];
    let pt2 = tmpPoints[1];
    let baseDir = new THREE.Vector2().subVectors(pt2, pt1);
    baseDir.normalize();
    const deleteIndices = [];
    for (let i = 1, len = tmpPoints.length; i + 1 < len; i++) {
        const dir = new THREE.Vector2().subVectors(tmpPoints[i + 1], tmpPoints[i]);
        dir.normalize();
        const v = baseDir.dot(dir);
        const isOne = Math.abs(v - 1) <= 0.01;
        if (isOne) {
            pt2 = tmpPoints[i + 1];
            deleteIndices.push(i);
        } else {
            pt1 = tmpPoints[i];
            pt2 = tmpPoints[i + 1];
        }
        baseDir = new THREE.Vector2().subVectors(pt2, pt1);
        baseDir.normalize();
    }

    if (!deleteIndices?.length) {
        return tmpPoints;
    }
    const newPoints = [];
    tmpPoints.forEach((pt, i) => {
        if (!deleteIndices.includes(i)) {
            newPoints.push(pt);
        }
    });
    return newPoints;
}

export const convertDomPosToCanvasPos = (domPos, scene2D, originCenter = true) => {
    const canvas = scene2D.getNativeCanvas();
    if (!canvas) {
        return domPos;
    }
    const canvasStyle = window.getComputedStyle(canvas, null);
    const cssWidth = parseFloat(canvasStyle['width']) || canvas.width;
    const cssHeight = parseFloat(canvasStyle['height']) || canvas.height;
    const scaleX = canvas.width / cssWidth;
    const scaleY = canvas.height / cssHeight;

    const canvasRect = canvas.getBoundingClientRect();

    const x = (domPos.x - canvasRect.left) * scaleX;
    const y = (domPos.y - canvasRect.top) * scaleY;

    if (originCenter) {
        const w = scene2D.getSourceWidth();
        const h = scene2D.getSourceHeight();
        return {
            x: x - (w / 2.0),
            y: (h / 2.0) - y
        };
    }

    return {
        x,
        y
    };
}

export const generatePassingPointsFor2D = (
    fromPos,
    toPos,
    type = '2D'
) => {

    const fn = utilToolObj.getFn('generatePassPoints');
    if(fn){
        return fn(fromPos, toPos, type);
    }else{

        const data = [];
        const split1 = 0.2;
        if (type === '3D') {
            data.push([fromPos[0], fromPos[1], 0]);
            data.push([fromPos[0], fromPos[1] + (toPos[1] - fromPos[1]) * split1, 0]);
            data.push([toPos[0], fromPos[1] + (toPos[1] - fromPos[1]) * split1, 0]);
            data.push([toPos[0], toPos[1], 0]);
        }
        if (type === '2D') {
            data.push([fromPos[0], fromPos[1], 0]);
            data.push([fromPos[0], fromPos[1] + (toPos[1] - fromPos[1]) * split1, 0]);
            data.push([toPos[0], fromPos[1] + (toPos[1] - fromPos[1]) * split1, 0]);
            data.push([toPos[0], toPos[1], 0]);
        }
        return data;
    }
}

export const unmountDomSelf = (element) => {
    const parentNode = element?.parentNode;
    parentNode && parentNode.removeChild(element);
}

export const sleep = (ms) => {
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve();
        }, ms);
    })
}

export const drawXCross = (ctx, x, y, l = 10) => {
    ctx.beginPath();
    ctx.moveTo(x - l, y - l);
    ctx.lineTo(x + l, y + l);
    ctx.moveTo(x + l, y - l);
    ctx.lineTo(x - l, y + l);
    ctx.closePath();
}

export const getDirectionByRotateStep = (srcDir, step) => {
    switch (srcDir) {
        case 'top':
            switch (step) {
                case 1:
                    return 'right';
                case 2:
                    return 'bottom';
                case 3:
                    return 'left';
                case 0:
                    return 'top';
                case -1:
                    return 'left';
                case -2:
                    return 'bottom';
                case -3:
                    return 'right';
            }
            break;
        case 'right':
            switch (step) {
                case 1:
                    return 'bottom';
                case 2:
                    return 'left';
                case 3:
                    return 'top';
                case 0:
                    return 'right';
                case -1:
                    return 'top';
                case -2:
                    return 'left';
                case -3:
                    return 'bottom';
            }
            break;
        case 'bottom':
            switch (step) {
                case 1:
                    return 'left';
                case 2:
                    return 'top';
                case 3:
                    return 'right';
                case 0:
                    return 'bottom';
                case -1:
                    return 'right';
                case -2:
                    return 'top';
                case -3:
                    return 'left';
            }
            break;
        case 'left':
            switch (step) {
                case 1:
                    return 'top';
                case 2:
                    return 'right';
                case 3:
                    return 'bottom';
                case 0:
                    return 'left';
                case -1:
                    return 'bottom';
                case -2:
                    return 'right';
                case -3:
                    return 'top';
            }
            break;
    }
}

export const toSavePoint = (pt, scene2D) => {
    const width = scene2D?.getSourceWidth();
    const height = scene2D?.getSourceHeight();
    return new THREE.Vector2(
        pt.x - (width / 2.0),
        (height / 2.0) - pt.y,
    )
}

export const isSegIntersectRect = (pt1, pt2, rect) => {
    const x1 = pt1.x;
    const y1 = pt1.y;
    const x2 = pt2.x;
    const y2 = pt2.y;
    const rx = rect.x;
    const ry = rect.y;
    const rw = rect.width;
    const rh = rect.height;

    if ((x1 >= rx && x1 <= rx + rw && y1 >= ry && y1 <= ry + rh) ||
        (x2 >= rx && x2 <= rx + rw && y2 >= ry && y2 <= ry + rh)) {
        return true; // Segment endpoint inside rectangle
    }

    // Check if segment intersects with any side of the rectangle
    // Rectangle sides coordinates
    const rectTop = ry;
    const rectBottom = ry + rh;
    const rectLeft = rx;
    const rectRight = rx + rw;

    // Segment endpoints coordinates
    const segMinX = Math.min(x1, x2);
    const segMaxX = Math.max(x1, x2);
    const segMinY = Math.min(y1, y2);
    const segMaxY = Math.max(y1, y2);

    // Check if the segment intersects with any of the rectangle's sides
    // Horizontal sides
    if (segMaxX >= rectLeft && segMinX <= rectRight &&
        (segMinY <= rectBottom && segMaxY >= rectTop)) {
        return true;
    }
    // Vertical sides
    if (segMaxY >= rectTop && segMinY <= rectBottom &&
        (segMinX <= rectRight && segMaxX >= rectLeft)) {
        return true;
    }

    // If none of the above conditions are met, there's no intersection
    return false;
}

export const updatePinoutLink = (
    startDrawable,
    endDrawable,
    startAnchor,
    endAnchor,
    kyScene) => {
    const isSameDrawable = startDrawable.id === endDrawable.id;

    const lineHandler = new PinoutLineHandler();
    lineHandler.setDrawable(startDrawable, endDrawable);

    // try {
    //     const startHeadInfo = startAnchor.getHeadInfo();
    //     const endHeadInfo = endAnchor.getHeadInfo();
    //     const startRectPos = startHeadInfo.rect.position();
    //     const endRectPos = endHeadInfo.rect.position();
    //     const startPos = startHeadInfo.point;
    //     const endPos = endHeadInfo.point;
    //     const startDir = startHeadInfo.directionType;
    //     const endDir = endHeadInfo.directionType;
    //
    //     let points = [];
    //     if (isSameDrawable) {
    //         points = lineHandler
    //             .getPassingPointsOnSameNode(
    //                 startPos,
    //                 endPos,
    //                 startDir,
    //                 endDir
    //             );
    //     } else {
    //         const validDirection = lineHandler.isValidDirection(startDir, endDir);
    //         const start = validDirection ? startPos : startRectPos;
    //         const end = validDirection ? endPos : endRectPos;
    //         let onTop;
    //         let onRight;
    //         let intersectNodes = [];
    //         if (validDirection) {
    //             // 判断线条是否与其他预制件想交
    //             const nodes = kyScene.getAllNodes();
    //             nodes.forEach((node) => {
    //                 if (
    //                     node.id === startDrawable.id ||
    //                     node.id === endDrawable.id) {
    //                     return;
    //                 }
    //                 const d = node.getDrawable2D();
    //                 if(d){
    //                     const rect = d.getClientRect();
    //                     if (isSegIntersectRect(startPos, endPos, rect)) {
    //                         intersectNodes.push(d);
    //                     }
    //                 }
    //             });
    //
    //             const topPt = startDrawable.getDirectionByType('top');
    //             const rightPt = startDrawable.getDirectionByType('right');
    //
    //             onTop = startPos.y < rightPt.y;
    //             onRight = startPos.x > topPt.x;
    //
    //         }
    //         points = lineHandler
    //             .getPassingPointsDifferentNode(
    //                 start, end,
    //                 startDir, endDir,
    //                 {
    //                     startDrawable,
    //                     endDrawable,
    //                     intersectNodes,
    //                     onTop,
    //                     onRight
    //                 }
    //             );
    //         if (!validDirection) {
    //             points.unshift([startPos.x, startPos.y, 0]);
    //             points.push([endPos.x, endPos.y, 0]);
    //         }
    //     }
    //
    //     return points;
    // } catch (error) {
    //     console.log('pin error', error);
    //     return [];
    // }
}

// 转到笛卡尔坐标，canvas中心点为原点
export const viewPosToBusinessePos = (p, sw, sh) => {
    const w = sw;
    const h = sh;
    return new THREE.Vector3(
        p.x,
        -p.y,
        0
    );
}

// 转到笛卡尔坐标，canvas中心点为原点
export const viewPosToBusinessePosBak = (p, sw, sh) => {
    const w = sw;
    const h = sh;
    return new THREE.Vector3(
        p.x - (w / 2.0),
        (h / 2.0) - p.y,
        p.z
    );
}
